require 'active_support/inflector'
require 'pagination/helpers/tags'

module Pagination
  module Helpers
    class Paginator < Tag
      include ::ActionView::Context

      def initialize(template, window: Pagination.config.window, **options)
        @template, @options, @views_prefix = template, options, options[:views_prefix]
        @window_options = @options.merge(window: window)
        @window_options[:current_page] = @options[:current_page] = PageProxy.new(@window_options, options[:current_page_num])

        #要实现跨多个<％％>标签，@output_buffer就要赋值，不然会报错
        # https://stackoverflow.com/questions/55761648/ruby-dsl-used-across-multiple-tags-or-multiple-lines
        @output_buffer = if defined?(::ActionView::OutputBuffer)
                           ::ActionView::OutputBuffer.new
                         elsif template.instance_variable_get(:@output_buffer)
                           template.instance_variable_get(:@output_buffer).class.new
                         else
                           ActiveSupport::SafeBuffer.new
                         end
      end

      def render(&block)
        instance_eval(&block) if @options[:total_pages] > 1
        @output_buffer.presence
      end

      def to_s
        super @window_options.merge paginator: self
      end

      def each_page
        # window=3
        # … 2 3 4 5 6 7 8 …  当前页5
        # 1 2 3 4 5 6 …   当前页1
        range_start = @window_options[:current_page_num] - @window_options[:window] - 1
        range_end = @window_options[:current_page_num] + @window_options[:window] + 1
        range_start = 1 if range_start < 1
        range_end = @window_options[:total_pages] if range_end > @window_options[:total_pages]
        (range_start..range_end).each do |page|
          yield PageProxy.new(@window_options, page)
        end
      end

      def page_tag(page)
        Page.new(@template, **@options.merge(page: page))
      end

      %w(first_page last_page prev_page next_page gap).each do |tag|
        eval <<-RUBY
          def #{tag}_tag
           #{tag.classify}.new @template, **@options
          end
        RUBY
      end

      class PageProxy
        include Comparable

        def initialize(options, page)
          @options, @page = options, page
        end

        def number
          @page
        end

        def current?
          @page == current_page_num
        end

        def first?
          @page == 1
        end

        def last?
          @page == @options[:total_pages]
        end

        def prev?
          @page == current_page_num - 1
        end

        def rel
          return 'prev' if prev?
          return 'next' if next?
        end

        def next?
          @page == current_page_num + 1
        end

        def inside_window?
          (current_page_num - @page).abs <= @options[:window]
        end

        def out_of_range?
          @page < 1 || @page > @options[:total_pages]
        end

        def to_i
          number
        end

        def to_s
          number.to_s
        end

        def <=>(other)
          to_i <=> other.to_i
        end

        private
        def current_page_num
          @options[:current_page_num]
        end

      end
    end
  end
end